package com.power.filter;

import cn.hutool.json.JSONUtil;
import cn.hutool.jwt.JWTUtil;
import com.power.constant.Constant;
import com.power.model.TUser;
import com.power.result.R;
import com.power.service.RedisService;
import com.power.util.LoginInfoUtil;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Objects;

/**
 * @Author 海晨忆
 * @Des token验证的filter
 * @Date 2025/8/8 15:25
 */
@Component
public class TokenFilter extends OncePerRequestFilter {
    @Autowired
    private RedisService redisService;

    @Autowired
    private ThreadPoolTaskExecutor taskExecutor;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        response.setContentType("application/json");
        response.setCharacterEncoding("utf-8");
        String requestURI = request.getRequestURI();
        if (requestURI.equals("/api/login")) {
            //不需要登录的接口直接放过
            filterChain.doFilter(request, response);
        } else {
            //获取请求头中的token
            String token = null;
            if (requestURI.equals("/api/customer/exportExcel")) {
                token = request.getParameter("token");
            } else {
                token = request.getHeader("token");
            }
            if (!StringUtils.hasText(token)) {
                //请求token为空
                R fail = R.FAIL(901, "请求token不能为空");
                String failString = JSONUtil.toJsonStr(fail);
                response.getWriter().write(failString);
            } else {
                boolean verifyToken = false;
                try {
                    verifyToken = JWTUtil.verify(token, Constant.LOGIN_JWT_SECRET.getBytes(StandardCharsets.UTF_8));
                } catch (Exception e) {
                    //token验证异常
                    R fail = R.FAIL(902, "token验证异常");
                    String failString = JSONUtil.toJsonStr(fail);
                    response.getWriter().write(failString);
                    return;
                }
                if (!verifyToken) {
                    //token验证失败
                    R fail = R.FAIL(902, "token验证失败");
                    String failString = JSONUtil.toJsonStr(fail);
                    response.getWriter().write(failString);
                } else {
//                    JWT jwt = JWTUtil.parseToken(token);
//                    TUser tUser = (TUser) jwt.getPayload("user");
//                    JSONObject payloads = JWTUtil.parseToken(token).getPayloads();
//                    String userJSON = payloads.get("user", String.class);
//                    TUser tUser = JSONUtil.toBean(userJSON, TUser.class);
                    TUser tUser = LoginInfoUtil.getUserFromToken(token);
                    String redisToken = redisService.getValue(Constant.REDIS_TOKEN_KEY + tUser.getId());
                    if (!StringUtils.hasText(token) || !Objects.equals(redisToken, token)) {
                        //登录过期
                        R fail = R.FAIL(903, "登录已过期，请重新登录!");
                        String failString = JSONUtil.toJsonStr(fail);
                        response.getWriter().write(failString);
                    } else {
                        //验证通过之后，需要在spring security的上下文对象中放置一个认证对象Authentication
                        //这样，框架才会认为该用户是认证过的
                        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(tUser, null, tUser.getAuthorities());
                        SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
                        //使用线程池异步刷新token
                        taskExecutor.execute(() -> {
                            redisService.expire(Constant.REDIS_TOKEN_KEY + tUser.getId(), 30 * 60);
                        });
                        //token验证通过
                        filterChain.doFilter(request, response);
                    }
                }
            }
        }


    }
}
